package com.bumptech.glide.manager;

import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.util.Util;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.AbilityPackage;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.ability.ILifecycle;
import ohos.app.AbilityContext;
import ohos.app.Context;
import org.jetbrains.annotations.NotNull;

/**
 * A collection of static methods for creating new {@link com.bumptech.glide.RequestManager}s or
 * retrieving existing ones from activities and fragment.
 */
public class RequestManagerRetriever {
  static final String FRAGMENT_TAG = "com.bumptech.glide.manager";
  private static final String TAG = "RMRetriever";

  private static final int ID_REMOVE_FRAGMENT_MANAGER = 1;
  private static final int ID_REMOVE_SUPPORT_FRAGMENT_MANAGER = 2;

  // Hacks based on the implementation of FragmentManagerImpl in the non-support libraries that
  // allow us to iterate over and retrieve all active Fragments in a FragmentManager.
  private static final String FRAGMENT_INDEX_KEY = "key";

  /** The top application level RequestManager. */
  private volatile RequestManager applicationManager;
  private final RequestManagerFactory factory;

  public RequestManagerRetriever( RequestManagerFactory factory) {
    this.factory = factory != null ? factory : DEFAULT_FACTORY;

  }

  @NotNull
  private RequestManager getApplicationManager(
      @NotNull Context context) {
    // Either an application context or we're on a background thread.
    if (applicationManager == null) {
      synchronized (this) {
        if (applicationManager == null) {
          // Normally pause/resume is taken care of by the fragment we add to the fragment or
          // activity. However, in this case since the manager attached to the application will not
          // receive lifecycle events, we must force the manager to start resumed using
          // ApplicationLifecycle.

          // TODO(b/27524013): Factor out this Glide.get() call.
          Glide glide = Glide.get(context);
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context);
        }
      }
    }

    return applicationManager;
  }
  private static boolean isActivityVisible(Context context){
    Ability activity = findActivity(context);
    return activity == null || !activity.isTerminating();
  }

  private static Ability findActivity(Context context){
    if(context instanceof  Ability){
      return (Ability)context;
    }else if(context instanceof AbilityContext){
      return  findActivity(((AbilityContext)context).getContext());
    }else{
      return null;
    }
  }

  @NotNull
  public RequestManager get(@NotNull Context context){
    if(context == null){
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    }
    /**
     * Lifecycle binding has a problem.The context obtained by component getContext() on the
     * abilitySlice page is not necessarily the abilitySlice object of the current page but
     * the abilitySlice object of the first page.
     * Therefore,improper use of the context may cause the lifecycle disorder and the Glide cannot
     * load data
     */
    //    else if(Util.isOnMainThread() && !(context instanceof AbilityPackage)){
    //      if(context instanceof  Ability){
    //        return  get((Ability)context);
    //      } else if(context instanceof AbilitySlice){
    //        return  get((AbilitySlice)context);
    //      }else if(context instanceof AbilityContext
    //              && ((AbilityContext)context).getContext().getApplicationContext() != null){
    //        return get(((AbilityContext)context).getContext());
    //      }else {}
    //    }
    return  getApplicationManager(context);
  }

  /**
   * RequestManager get
   * @param activity Ability
   * @return RequestManager
   */
  private RequestManager get(Ability activity){
    if(Util.isOnBackgroundThread()){
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      return  abilityGet(activity, isActivityVisible(activity));
    }
  }

  /**
   * RequestManager get
   * @param abilitySlice AbilitySlice
   * @return RequestManager
   */
  private RequestManager get(AbilitySlice abilitySlice){
    if(Util.isOnBackgroundThread()){
      return get(abilitySlice.getApplicationContext());
    } else {
      return  abilitySliceGet(abilitySlice);
    }
  }

  private RequestManager abilityGet(Ability activity, boolean isParentVisible){
    RequestManagerFragment current = getRequestManagerFragment(activity);
    RequestManager requestManager = current.getRequestManager();
    if(requestManager == null){
      Glide glide = Glide.get(activity);
      requestManager =
              factory.build(
                      glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), activity);
      if(isParentVisible){
        requestManager.onStart();
      }
      current.setRequestManager(requestManager);
    }
    return  requestManager;
  }

  private RequestManager abilitySliceGet(AbilitySlice slice){
    RequestManagerFragment current = getRequestManagerFragment(slice);
    RequestManager requestManager = current.getRequestManager();
    if(requestManager == null){
      Glide glide = Glide.get(slice.getApplicationContext());
      requestManager =
              factory.build(
                      glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), slice.getApplicationContext());
              if(((ILifecycle)slice).getLifecycle().getLifecycleState() != ohos.aafwk.ability.Lifecycle.Event.ON_BACKGROUND){
                requestManager.onStart();
              }
              current.setRequestManager(requestManager);
    }
    return  requestManager;
  }

  private RequestManagerFragment getRequestManagerFragment(Ability ability){
    RequestManagerFragment current = new RequestManagerFragment(((ILifecycle)ability).getLifecycle());
    return current;
  }

  private RequestManagerFragment getRequestManagerFragment(AbilitySlice abilitySlice){
    RequestManagerFragment current = new RequestManagerFragment(((ILifecycle)abilitySlice).getLifecycle());
    return current;
  }

  private static void assertNotDestroyed(Ability activity) {
    if(activity.isTerminating()){
      throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
    }
  }


  /** Used internally to create {@link RequestManager}s. */
  public interface RequestManagerFactory {
	@NotNull
    RequestManager build(
           @NotNull Glide glide,
           @NotNull Lifecycle lifecycle,
           @NotNull RequestManagerTreeNode requestManagerTreeNode,
           @NotNull Context context);
  }

  private static final RequestManagerFactory DEFAULT_FACTORY =
      new RequestManagerFactory() {
        @NotNull
        @Override
        public RequestManager build(
             @NotNull Glide glide,
             @NotNull Lifecycle lifecycle,
             @NotNull RequestManagerTreeNode requestManagerTreeNode,
             @NotNull Context context) {
          return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
        }
      };
}
